﻿
Partial Public Class fceslite4(Of THREADSAFE As _boolean)
    Private Function valid_cluster(ByVal id As Int64) As Boolean
        Return cs.availableIndex(id)
    End Function

    Private Function valid_head_cluster(ByVal id As Int64) As Boolean
        Return valid_cluster(id) AndAlso Not cs(id).has_prevCluster()
    End Function

    Private Function valid_chain_after(ByVal n As cluster4) As Boolean
        assert(Not n Is Nothing)
        Dim c As cluster4 = Nothing
        Return valid_cluster(n.prevClusterId()) AndAlso
               eva(c, cs(n.prevClusterId())) AndAlso
               c.has_nextCluster() AndAlso
               c.nextClusterId() = n.clusterId()
    End Function

    Private Function find_nextCluster(ByVal c As cluster4, ByRef n As cluster4) As Boolean
        assert(Not c Is Nothing)
        n = Nothing
        If c.has_nextCluster() AndAlso
           valid_cluster(c.nextClusterId()) AndAlso
           eva(n, cs(c.nextClusterId())) AndAlso
           (Not n.has_prevCluster() OrElse
            n.prevClusterId() = c.clusterId() OrElse
            Not valid_chain_after(n)) Then

            If n.prevClusterId() <> c.clusterId() Then
                n.prevClusterId() = c.clusterId()
            End If
            Return True
        Else
            If c.has_nextCluster() Then
                c.clear_nextClusterId()
            End If
            Return False
        End If
    End Function

    Private Function find_nextCluster(ByRef c As cluster4) As Boolean
        Return find_nextCluster(c, c)
    End Function

    Private Function foreach_cluster(ByVal id As Int64, ByVal d As _do(Of cluster4, Int64, Boolean)) As Boolean
        assert(Not d Is Nothing)
        If valid_head_cluster(id) Then
            Dim c As cluster4 = Nothing
            c = cs(id)
            Dim i As Int64 = 0
            While i < cs.size()
                If d(assert_return(Not c.free() OrElse Not c.has_nextCluster(), c), unref(i)) Then
                    If Not find_nextCluster(c) Then
                        Exit While
                    End If
                Else
                    Return False
                End If
                i += 1
            End While
            Return True
        Else
            Return False
        End If
    End Function

    Private Function foreach_cluster(ByVal id As Int64, ByVal d As _do(Of cluster4, Boolean)) As Boolean
        assert(Not d Is Nothing)
        Return foreach_cluster(id,
                               Function(ByRef c As cluster4, ByRef i As Int64) As Boolean
                                   Return d(c)
                               End Function)
    End Function

    Private Function foreach_nonempty_cluster(ByVal id As Int64,
                                              ByVal d As _do(Of cluster4, Int64, Int64, Boolean)) As Boolean
        assert(Not d Is Nothing)
        Dim i As Int64 = 0
        Return foreach_cluster(id,
                               Function(ByRef c As cluster4, ByRef j As Int64) As Boolean
                                   If c.empty() Then
                                       Return True
                                   Else
                                       Return d(c, unref(i), j) AndAlso
                                              eva(i, i + 1)
                                   End If
                               End Function)
    End Function

    Private Function foreach_nonempty_cluster(ByVal id As Int64,
                                              ByVal d As _do(Of cluster4, Int64, Boolean)) As Boolean
        assert(Not d Is Nothing)
        Return foreach_nonempty_cluster(id,
                                        Function(ByRef c As cluster4,
                                                ByRef nonfree As Int64,
                                                ByRef all As Int64) As Boolean
                                            Return d(c, nonfree)
                                        End Function)
    End Function

    Private Function foreach_nonempty_cluster(ByVal id As Int64,
                                              ByVal d As _do(Of cluster4, Boolean)) As Boolean
        assert(Not d Is Nothing)
        Return foreach_nonempty_cluster(id,
                                        Function(ByRef c As cluster4, ByRef i As Int64) As Boolean
                                            Return d(c)
                                        End Function)
    End Function

    Private Function sizeof_cluster(ByVal id As Int64, ByRef size As Int64) As Boolean
        Dim i As Int64 = 0
        Return foreach_nonempty_cluster(id,
                                        Function(ByRef c As cluster4) As Boolean
                                            i += c.used()
                                            Return True
                                        End Function) AndAlso
               eva(size, i)
    End Function

    Private Function nonempty_cluster_count(ByVal id As Int64, ByRef count As Int64) As Boolean
        Dim i As Int64 = 0
        Return foreach_nonempty_cluster(id,
                                       Function(ByRef c As cluster4) As Boolean
                                           i += 1
                                           Return True
                                       End Function) AndAlso
               eva(count, i)
    End Function

    Private Function each_nonempty_cluster_used(ByVal id As Int64,
                                                ByRef useds() As Int64,
                                                Optional ByRef nonempty_count As Int64 = 0) As Boolean
        If nonempty_cluster_count(id, nonempty_count) Then
            Dim us(nonempty_count - 1) As Int64
            useds = us
            Return foreach_nonempty_cluster(id,
                                            Function(ByRef c As cluster4, ByRef i As Int64) As Boolean
                                                us(i) = c.used()
                                                Return True
                                            End Function)
        Else
            Return False
        End If
    End Function

    Private Sub useds_offsets(ByVal useds() As Int64, ByRef offsets() As Int64)
        assert(Not useds Is Nothing)
        ReDim offsets(useds.Length() - 1)
        offsets(0) = 0
        For i = 1 To useds.Length() - 1
            offsets(i) = useds(i - 1) + offsets(i - 1)
        Next
    End Sub

    Private Function find_next_free_cluster(ByVal expectSize As Int64) As cluster4
        Dim rtn As cluster4 = Nothing
        If free_cs.empty() Then
            lock()
            Dim end_diskoffset As Int64 = 0
            If cs.empty() Then
                end_diskoffset = 0
            Else
                end_diskoffset = cs.rbegin().get().end_diskoffset()
            End If
            rtn = New cluster4(cs.size(), end_diskoffset, expectSize, vd)
            cs.push_back(rtn)
            unlock()
        Else
            rtn = free_cs.pop()
        End If
        assert(rtn.free())
        Return rtn
    End Function

    Private Function find_next_free_cluster_and_chain(ByVal expectSize As Int64, ByVal last As cluster4) As cluster4
        assert(Not last Is Nothing)
        Dim rtn As cluster4 = Nothing
        rtn = find_next_free_cluster(expectSize)
        assert(Not rtn Is Nothing)
        rtn.chain_after(last)
        Return rtn
    End Function
End Class
